# coding=utf-8
import cv2
import numpy as np
import struct
import serial
import time

com = serial.Serial(
        port="/dev/ttyTHS1",
        baudrate=115200,
        bytesize=serial.EIGHTBITS,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
)

time.sleep(1)

def send_data(Cx):
    tmp = struct.pack("<BBhB", 0x2C, 0x12, int(Cx), 0x5B)
    com.write(tmp)

# 初始化摄像头
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

ROI_SATRT = (320, 0)
ROI_END = (320, 480)

scan_line_x = 320

up_edge_y = 0
down_edge_y = 0

flag_up = 0
flag_down = 0

center_point_y = 0

lower_threshold = 65
upper_threshold = 80

# def getpos(event,x,y,flags,param):
#     if event==cv2.EVENT_LBUTTONDOWN: #定义一个鼠标左键按下去的事件
#         print(closed[y,x])
#         print((x,y))

def img_pre_process(oringnal_img):

    # 高斯滤波
    blurred = cv2.GaussianBlur(oringnal_img, (15, 15), 0)

    # 在有反光的情况下初步二值化
    _, binary_image = cv2.threshold(blurred, thresh=80, maxval=255, type=cv2.THRESH_BINARY)

    # 使用开运算去除小的噪声点
    kernel_open = np.ones((9, 9), np.uint8)
    opened = cv2.morphologyEx(binary_image, cv2.MORPH_OPEN, kernel_open)

    # 使用闭运算连接可能被断开的黑线
    kernel_close = np.ones((7, 7), np.uint8)
    closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel_close)

    return closed

def reflection_process(gray_img, processed_img):

    # 提取反光区域，用inrange()能够特定提取反光区域而不提取白色背景，在进行and操作的时候就不会影响原来图像的背景，这里用threshold()效果不行
    glare_mask = cv2.inRange(gray_img, lower_threshold, upper_threshold)

    # 膨胀以确保覆盖所有反光区域
    glare_mask = cv2.dilate(glare_mask, None, iterations=2)

    # 将提取的反光区域取反，与原图像进行and操作
    anti_glare_image = cv2.bitwise_and(processed_img, cv2.bitwise_not(glare_mask))

    return anti_glare_image

while True:
    ret, frame = cap.read()

    if not ret:
        break

    cv2.rectangle(frame, ROI_SATRT, ROI_END, (255, 255, 0), 1)

    # 转换为灰度图（关键步骤）
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    height, width = gray.shape

    # 图像预处理
    pre_processed_img = img_pre_process(gray)

    # 反光处理：通过阈值提取反光区域并用黑色填充
    final_img = reflection_process(gray, pre_processed_img)

    line_data = final_img[:, scan_line_x]  # 使用处理后的图像进行后续处理

    # scan from up to down
    for column in range(0, height - 1, 1):
        y_up = int(line_data[column])
        y_down = int(line_data[column + 1])
        
        if y_up - y_down == 255 and flag_up + flag_down == 0:
            up_edge_y = column
            flag_up = 1
        elif y_down - y_up == 255 and flag_down == 0 and flag_up == 1:
            down_edge_y = column
            flag_down = 1
    
    if flag_up + flag_down == 2:
        center_point_y = int((up_edge_y + down_edge_y) / 2)
        send_data(center_point_y)
        print(center_point_y)
        flag_down = flag_up = 0
        cv2.circle(frame, (scan_line_x, center_point_y), 5, (255, 255, 100), -1)
        center_point_y = 0
    elif flag_up == 1 and flag_down == 0:
        flag_down = flag_up = 0
        send_data(int((height + up_edge_y) / 2))
        print(int((height + up_edge_y) / 2))
        cv2.circle(frame, (scan_line_x, int((height + up_edge_y) / 2)), 5, (255, 100, 100), -1)
        print("only up edge!!!") 
    elif flag_up + flag_down == 0:
        send_data(0)
        print("white")

    cv2.imshow('final_img', final_img)  # 显示处理后的图像

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()